package com.hnblc.blcwms.rest.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.hnblc.blcwms.client.service.HttpClientService;
import com.hnblc.blcwms.common.constant.CommonConst;
import com.hnblc.blcwms.common.constant.StringPool;
import com.hnblc.blcwms.common.interaction.RestResponse;
import com.hnblc.blcwms.common.utils.WmsTimeUtils;
import com.hnblc.blcwms.common.utils.encrypt.BASE64;
import com.hnblc.blcwms.common.utils.encrypt.MD5Util;
import com.hnblc.blcwms.persistent.interfaces.business.dto.StatusReadyTask;
import com.hnblc.blcwms.persistent.interfaces.business.entity.ErpExpStatus;
import com.hnblc.blcwms.persistent.interfaces.business.service.IErpExpStatusService;
import com.hnblc.blcwms.persistent.interfaces.client.entity.ClientInfo;
import com.hnblc.blcwms.rest.dto.restInteraction.EncryptRequest;
import com.hnblc.blcwms.serviceapi.api.dto.ration.status.ExpErrorResultDto;
import com.hnblc.blcwms.serviceapi.api.dto.ration.status.ExpressStatusDto;
import com.hnblc.blcwms.serviceapi.api.enums.code.RationUpStatusCodeEnum;
import com.hnblc.blcwms.serviceapi.api.service.IRationUpService;
import org.apache.http.entity.ContentType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.*;


/**
 * @ClassName: RationUpService
 * @Description: TODO
 * @Author: linsong
 * @Date: 2019/11/1
 * @Version: V1.0
 */
@Service
public class RationUpService implements IRationUpService {

    Logger logger = LoggerFactory.getLogger(RationUpService.class);

    @Autowired
    ObjectMapper objectMapper;
    @Autowired
    IErpExpStatusService erpExpStatusService;
    @Autowired
    HttpClientService httpClientService;

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void sendRetionUp() {
        List<StatusReadyTask> statusList =  erpExpStatusService.listReadyTask();

        //目的地址客户端信息
        Map<String, ClientInfo> clientMap = new HashMap<>();
        //目的地址请求列表
        Map<String,List<StatusReadyTask>> requestMap = new HashMap<>();
        //把需要反馈状态的订单，根据目的URL分组
        for (StatusReadyTask item:statusList){

            //客户端信息MAP
            if(!clientMap.containsKey(item.getClientReturnUrl())){
                ClientInfo clientInfo = new ClientInfo();
                clientInfo.setClientId(item.getClientId());
                clientInfo.setClientKey(item.getClientKey());
                clientMap.put(item.getClientReturnUrl(),clientInfo);
            }
            //待发状态列表MAP
            if(requestMap.containsKey(item.getClientReturnUrl())){
                requestMap.get(item.getClientReturnUrl()).add(item);
            }else {
                List<StatusReadyTask> statusSendList = new ArrayList<>();
                statusSendList.add(item);
                requestMap.put(item.getClientReturnUrl(),statusSendList);
            }
        }


        //反馈成功转历史通知单集合
        List<ErpExpStatus> deliverNoToHis = new ArrayList<>();
        //循环执行反馈状态任务
        Iterator<String> statIt = requestMap.keySet().iterator();
        while (statIt.hasNext()){
            String url = statIt.next();
            List<StatusReadyTask> postList = requestMap.get(url);
            logger.info("Start [Push ["+postList.size()+"]] delivery status info to "+url);
            RestResponse<List<ExpErrorResultDto>> result = this.processRationRequest(url,clientMap.get(url),postList);
            if (result!=null && RestResponse.RESP_CODE_SUCCESS.equalsIgnoreCase(result.getResultCode())){
                deliverNoToHis.addAll(postList);
            }else if(result!=null && (RestResponse.RESP_CODE_FAILURE.equalsIgnoreCase(result.getResultCode())||"0".equalsIgnoreCase(result.getResultCode()))){
                List<ExpErrorResultDto> errList = result.getBusiness_data();
                if (errList==null || errList.size()==0){
                    logger.error("Error occurred when processing post express status result:[empty error detail list.[[URL"+url+"]]");
                }else {
                    for (int i=postList.size()-1;i>=0;i--){
                        for (ExpErrorResultDto errItem:errList){
                            if (errItem.getOrderNo().equals(postList.get(i).getDeliverObj())&& !"ERROR-12-000001".equalsIgnoreCase(errItem.getErrorCode())&&!"RESP-21-00001".equalsIgnoreCase(errItem.getErrorCode())){
                                logger.error("Error occurred when processing post express status result:[[orderNo:"+errItem.getOrderNo()+"],[errorDetail:"+errItem.getErrorDetail()+"].[URL"+url+"]]");
                                postList.remove(i);
                                break;
                            }
                        }
                    }
                }
                logger.info("Sucess [Push ["+postList.size()+"]] delivery status info to "+url);
                deliverNoToHis.addAll(postList);
            }
        }

        if (deliverNoToHis.size()>0){
            erpExpStatusService.insertHistory(deliverNoToHis);

            logger.debug("*****************************[[History Data Save Success]]********************************\n");
            List<String> deliverNos= new ArrayList<String>();
            for (ErpExpStatus item:deliverNoToHis){
                deliverNos.add(item.getDeliverNo());
            }
            erpExpStatusService.remove(new QueryWrapper<ErpExpStatus>().in("deliver_no",deliverNos));
            logger.info("*******************[["+deliverNoToHis.size()+" Order status have bean sent at "+WmsTimeUtils.getCurrentDatetime()+"]]**********************");
            logger.debug("*****************************[[Ready Data Delete Success]]********************************\n" );
        }
    }



    private RestResponse<List<ExpErrorResultDto>> processRationRequest(String url, ClientInfo clientInfo, List<StatusReadyTask> statusDtos){
        EncryptRequest request = new EncryptRequest();
        List<ExpressStatusDto> statusList = new ArrayList<ExpressStatusDto>();
        for (ErpExpStatus item:statusDtos){
            //构造报文
            ExpressStatusDto statusDto = new ExpressStatusDto();
            //TODO 增加向客户反馈字段
//            临时构造货主
            statusDto.setOwnerNo(item.getCustNo());
//            statusDto.setCustomNo(item.getCustNo());
//            statusDto.setLoadProp
// oseNo(item.getLoadproposeNo());
//            statusDto.setDeliverNo(item.getDeliverNo());
            statusDto.setOrderNo(item.getDeliverObj());
            statusDto.setLogisticNo(item.getLogisticNo());
//            statusDto.setSendName(item.getWorkerName());
//            statusDto.setOperateDate(item.getOperateDate());
            statusDto.setStatus(RationUpStatusCodeEnum.SENT.code());
            statusList.add(statusDto);
        }
        request.setClientId(clientInfo.getClientId());   //设置客户端ID
        request.setTimestamp(new Long(WmsTimeUtils.datatimeToTimestamp(LocalDateTime.now())).toString());
        request.setVersion(CommonConst.SYS_VERSION);
        try {
            String businessData = objectMapper.writeValueAsString(statusList);
            logger.debug("*****************************STATUS LIST FOR BUSINESS DATA JSON STRING********************************\n" + businessData);
            String businessDaStr = BASE64.encryptBASE64(businessData.getBytes(StringPool.CHARSET_UTF8));
            request.setBusinessData(businessDaStr);
            logger.debug("*****************************STATUS LIST FOR BUSINESS DATA BASE64 STRING********************************\n" + businessDaStr);
            request.setSignature(MD5Util.md5Encode(businessDaStr + request.getTimestamp() + clientInfo.getClientKey()));
            String param = objectMapper.writeValueAsString(request);
            logger.debug("*****************************ERP RATION STATUS FINAL SENT STRING********************************\n" + param);
            String result = httpClientService.sendHttpPost(url, param, ContentType.APPLICATION_JSON);
            logger.debug("*****************************ERP RATION STATUS FINAL RECEIVE STRING********************************\n" + result);
//            JavaType javaType = objectMapper.getTypeFactory().constructParametricType(RestResponse.class,ArrayList.class,ExpErrorResultDto.class);
            return objectMapper.readValue(result, new TypeReference<RestResponse<List<ExpErrorResultDto>>>(){});
//            return objectMapper.readValue(result,javaType);
        }catch (Exception e){
            logger.error("ERROR OCCURRED WHEN POST EXPRESS STATUS URL:\""+url+"\" ,DETAIL:"+e.getMessage(),e);
        }
        return null;
    }
}
